from contextlib import asynccontextmanager

try:
    import os
    import sys
    import httpx
    import uvicorn
    from fastapi import FastAPI, HTTPException, Request, Response
    from fastapi.middleware.cors import CORSMiddleware
    from fastapi.responses import RedirectResponse
    from starlette import status
    from apscheduler.triggers.interval import IntervalTrigger
    from logger import logger
    from project.user.auth.auth import auth_api
    from project.user.user import user_api

    from project.database import Base, engine, async_session_factory, init_db
    from util import scheduler

    root_path = os.getcwd()
    sys.path.append(root_path)

except Exception as e:
    logger.logger.error("启动时失败，失败原因：{}".format(str(e)))
    input("启动失败，失败原因：{}（按下回车退出程序）".format(str(e)))
    sys.exit()


@asynccontextmanager
async def lifespan(my_app: FastAPI):
    """
    项目启动和关闭时要执行的操作
    :param my_app:
    :return:
    """
    # 项目启动时的操作
    await init_db()  # 若没有数据库表，则初始化数据库表
    scheduler.add_job(keep_alive, IntervalTrigger(minutes=5))
    scheduler.start()

    yield

    # 项目关闭时的操作
    scheduler.shutdown()  # 关闭定时任务


app = FastAPI(
    title='FastAPI脚手架',
    description='FastAPI脚手架在线接口文档',
    version='1.0.0',
    docs_url='/docs',
    lifespan=lifespan
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许的来源，使用 "*" 表示允许所有来源
    allow_credentials=True,  # 允许携带凭据，例如 Cookies
    allow_methods=["*"],  # 允许的 HTTP 方法
    allow_headers=["*"],  # 允许的请求标头
)

app.include_router(auth_api, prefix='/auth', tags=['用户授权操作'])
app.include_router(user_api, prefix='/user', tags=['用户操作'])


async def keep_alive():
    """
    定时任务，用于保持链接有效
    :return:
    """
    async with httpx.AsyncClient() as client:
        try:
            await client.get("http://127.0.0.1:5555/keep_alive")
        except Exception as e:
            logger.logger.error("连接失效：{}".format(str(e)))


@app.get("/keep_alive")
async def keep_alive_endpoint():
    return {"message": "alive!"}


@app.middleware("http")
async def db_session_middleware(request: Request, call_next):
    async with async_session_factory() as session:
        request.state.db = session
        try:
            response = await call_next(request)
            await session.commit()
            return response
        except HTTPException as he:
            raise he
        except Exception as e:
            await session.rollback()
            logger.logger.error("未知的系统异常，错误原因：{}".format(str(e)))
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=str(e)
            )


@app.get('/')
async def index():
    return RedirectResponse(url="/docs")


if __name__ == '__main__':
    try:
        uvicorn.run(app, host='127.0.0.1', port=8888, reload=False)

    except Exception as e:
        logger.logger.error("启动时失败，失败原因：{}".format(str(e)))
        input("启动失败，失败原因：{}（按下回车退出程序）".format(str(e)))
        sys.exit()
